package com.boot.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.util.Base64;
import java.util.Date;
import java.util.Map;

/**
 * JWT 工具类：用于生成、解析和验证 JWT Token
 */
@Component
public class JwtUtil {

    @Value("${jwt.secret}")
    private String secretString;

    @Value("${jwt.expiration-hours:2}")
    private long expirationHours;

    private SecretKey secretKey;

    // 使用 @PostConstruct 初始化 key，避免字段未注入就使用
    @PostConstruct
    public void init() {
        if (secretString == null || secretString.trim().isEmpty()) {
            throw new IllegalArgumentException("JWT 密钥未配置，请检查 application.properties 中 jwt.secret");
        }
        // 强制要求 base64 解码后的原始字节长度 ≥ 64 bytes（512 bits）
        byte[] decoded = Base64.getDecoder().decode(secretString);
        if (decoded.length < 64) {
            throw new IllegalArgumentException("JWT secret 必须至少 512 bits (64 bytes)");
        }
        this.secretKey = Keys.hmacShaKeyFor(secretString.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 生成 JWT Token
     */
    public String generateToken(Map<String, Object> claims) {
        Instant now = Instant.now();
        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(Date.from(now))
                .setExpiration(Date.from(now.plus(Duration.ofHours(expirationHours))))
                .signWith(secretKey, SignatureAlgorithm.HS512)
                .compact();
    }

    /**
     * 解析 Token
     */
    public Claims parseToken(String token) throws JwtException {
        return Jwts.parserBuilder()
                .setSigningKey(secretKey)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 从 Claims 中提取 userId
     */
    public Long getUserId(Claims claims) {
        return ((Number) claims.get("userId")).longValue();
    }

    /**
     * 从 Claims 中提取 username
     */
    public String getUsername(Claims claims) {
        return claims.get("username", String.class);
    }

    /**
     * 获取过期时间（供外部检查或调试）
     */
    public Date getExpirationDate(Claims claims) {
        return claims.getExpiration();
    }

    /**
     * 判断 token 是否已过期
     */
    public boolean isTokenExpired(Claims claims) {
        return claims.getExpiration().before(new Date());
    }
}
